﻿using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using GestureMatching.DataStructure;
using Microsoft.Kinect;
using Microsoft.Samples.Kinect.WpfViewers;

namespace GestureMatching
{
    public class KinectOperator
    {
        private bool kinectStatus = false;
        const int skeletonCount = 6;
        Skeleton[] allSkeletons = new Skeleton[skeletonCount];
        DateTime previousDateTime = DateTime.Now;

        private static KinectOperator kinectOperator = null;

        KinectSensorChooser kinectSensorChooser;
        ListBox outputListBox;

        public static KinectOperator Me(KinectSensorChooser kinectSensorChooser)
        {
            if (kinectOperator == null)
            {
                kinectOperator = new KinectOperator();
                kinectOperator.kinectSensorChooser = kinectSensorChooser;
            }

            return kinectOperator;
        }

        public void InitializeOutputListBox(ListBox outputListBox)
        {
            this.outputListBox = outputListBox;
        }

        public bool GetKinectStatus()
        {
            return kinectStatus;
        }

        public TimingQueue CollectGesture()
        {
            TimingQueue gesture = new TimingQueue();
            //TODO:Complete Code which collect gesture.

            return gesture;
        }

        public void InitializeKinectOperator()
        {
            kinectSensorChooser.KinectSensorChanged += new DependencyPropertyChangedEventHandler(AfterKinectSensorChanged);
        }

        public void AfterKinectSensorChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            KinectSensor oldSensor = (KinectSensor)e.OldValue;
            StopKinect(oldSensor);

            KinectSensor sensor = (KinectSensor)e.NewValue;
            if (sensor == null)
            {
                return;
            }
            sensor.SkeletonStream.Enable();

            sensor.AllFramesReady += new EventHandler<AllFramesReadyEventArgs>(AfterSensorAllFramesReady);
            sensor.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);
            sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);

            try
            {
                sensor.Start();
                kinectStatus = true;
            }
            catch (System.IO.IOException)
            {
                kinectSensorChooser.AppConflictOccurred();
            }
        }

        public void AfterSensorAllFramesReady(object sender, AllFramesReadyEventArgs e)
        {
            if (!kinectStatus)
            {
                return;
            }

            //Get a skeleton
            Skeleton firstSkeleton = GetFirstSkeleton(e);
            if (firstSkeleton == null)
            {
                return;
            }

            TimingNode tempTimingNode = new TimingNode();
            tempTimingNode.data = firstSkeleton.Joints[JointType.HandLeft].Position;
            if (previousDateTime.Subtract(tempTimingNode.createTime).Milliseconds < -500)
            {
                Console.WriteLine(tempTimingNode.ToString());
                outputListBox.Items.Add(tempTimingNode.ToString());
                previousDateTime = tempTimingNode.createTime;
            }
        }

        public Skeleton GetFirstSkeleton(AllFramesReadyEventArgs e)
        {
            using (SkeletonFrame skeletonFrameData = e.OpenSkeletonFrame())
            {
                if (skeletonFrameData == null)
                {
                    return null;
                }

                skeletonFrameData.CopySkeletonDataTo(allSkeletons);

                //get the first tracked skeleton
                Skeleton firstSkeleton = (from s in allSkeletons
                                          where s.TrackingState == SkeletonTrackingState.Tracked
                                          select s).FirstOrDefault();

                return firstSkeleton;
            }
        }

        public void StopKinect(KinectSensor sensor)
        {
            if (sensor != null)
            {
                if (sensor.IsRunning)
                {
                    sensor.Stop();

                    if (sensor.AudioSource != null)
                    {
                        sensor.AudioSource.Stop();
                    }

                    kinectStatus = false;
                }
            }
        }

        public void CloseKinectOperator()
        {
            StopKinect(kinectSensorChooser.Kinect);
        }
    }
}